import tensorflow as tf

# 同一个存储，从不同的角度观察数据，可以产生不同的视图

x = tf.range(96)
x = tf.reshape(x, [2, 4, 4, 3])
print(x)

# tensorflow 中可通过张量的ndim和shape获取张量维度和形状
tf.reshape(x, [2, -1])  # 其中的-1  代表当前轴上的长度需要根据张量总元素不变的法则自动推导

x = tf.random.uniform([28, 28], maxval=10, dtype=tf.int32)
# 可在指定的axis轴前可以插入一个新的维度，axis为正在当前维度之前添加维度，axis为负在当前维度之后添加维度
print('在添加宽后面的维度之前', x.shape)
x = tf.expand_dims(x, axis=2)  # axis=2表示在宽维度后面的一个维度
print('在添加宽后面的维度之后，添加高前面维度之前', x.shape)
x = tf.expand_dims(x, axis=0)  # axis=0表示在高维度前面的一个维度
print('添加高前面维度之后', x.shape)

# 删除维度，当不指定维度参数axis时，会默认删除所有长度为1的维度，
# 所以防止意外删除，一般需要逐一指定维度删除
print('删除图片数量维度之前', x.shape)
x = tf.squeeze(x, axis=0)  # 删除图片的数量维度
print('删除图片数量维度之后', x.shape)

# 交换维度
print('交换维度之前', x.shape)
# perm参数为按照交换前各维度的索引构造的需要交换的顺,
# 例如：原来为 [0,1,2]想将最后一维和第一维交换perm为[2，1，0]
x = tf.transpose(x, perm=(2, 1, 0))
print('交换维度之后', x.shape)

# 数据复制  tf.tile 会创建一个新的张量来保存复制后的张量,
# 会导致大量的io读写，代价较高，轻量级的复制，看下面的Broadcasting
b = tf.constant([1, 2])
print('添加维度之前', b.shape)
b = tf.expand_dims(b, axis=0)
print('添加维度之后，复制维度之前', b.shape)
b = tf.tile(b, multiples=[2, 1])  # 表示在axis=0维度复制一次，在axis=1维度不复制
print('复制维度之后', b.shape)

# 通过tf.broadcast_to(a,new_shape)显示地执行自动扩展（有一个普适性的判断）,
# 一般在处理不同shape张量的时候，会隐式调用Broadcasting机制将各张量扩展成一个公共的shape在进行计算
A = tf.random.normal([4, 1])
print('复制维度之前', A.shape)
A = tf.broadcast_to(A, [2, 3, 4, 2])
print('复制维度之后', A.shape)
